<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>MaryTTS 流式语音合成</title>
</head>
<body>
<h1>WebSocket 实时语音合成演示</h1>
<div style="margin-bottom: 20px; display: flex; align-items: center; gap: 10px;">
  <button id="connectBtn" onclick="connect()" style="padding: 8px 16px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">连接</button>
  <button id="disconnectBtn" onclick="disconnect()" disabled style="padding: 8px 16px; background: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer;">断开</button>
  <span id="status" style="padding: 8px 16px; background: #e0e0e0; border-radius: 4px; font-weight: bold;">未连接</span>
</div>
<div style="margin-bottom: 20px;">
  <textarea id="textInput" placeholder="输入你想说的话..." style="width: 100%; height: 150px; padding: 12px; box-sizing: border-box; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; resize: vertical;"></textarea>
  <button onclick="sendText()" style="margin-top: 10px; padding: 8px 16px;">发送</button>
</div>

<div style="margin-top: 30px; width: 100%;">
  <audio id="audioPlayer" controls autoplay style="width: 100%;"></audio>
</div>

<script>
    let socket;
    let audioQueue = [];
    let isPlaying = false;

    function updateStatus(status) {
      const statusEl = document.getElementById('status');
      statusEl.textContent = status;
      statusEl.style.background = status === '已连接' ? '#4CAF50' : '#ccc';
      document.getElementById('connectBtn').disabled = status === '已连接';
      document.getElementById('disconnectBtn').disabled = status !== '已连接';
    }

    function playNextAudio() {
      if (audioQueue.length > 0 && !isPlaying) {
        isPlaying = true;
        const {url, audioPlayer} = audioQueue.shift();
        
        audioPlayer.onended = () => {
          isPlaying = false;
          playNextAudio();
        };
        
        audioPlayer.src = url;
        audioPlayer.play().catch(e => console.log('播放失败:', e));
      }
    }

    function connect() {
      socket = new WebSocket("ws://localhost:8080/stream");
      socket.onopen = () => {
        console.log("WebSocket 已连接");
        updateStatus('已连接');
      };

      socket.onmessage = function(event) {
        console.log("received");
        const response = JSON.parse(event.data);
        if (response.audio) {
          const audioBlob = b64toBlob(response.audio, 'audio/wav');
          const url = URL.createObjectURL(audioBlob);
          const audioPlayer = document.getElementById('audioPlayer');
          console.log(url);
          
          // 重置事件监听器
          audioPlayer.oncanplaythrough = null;
          audioPlayer.onerror = null;
          
          // 设置错误处理
          audioPlayer.onerror = () => {
            console.error('音频加载失败:', audioPlayer.error);
            isPlaying = false;
            playNextAudio();
          };
          
          // 添加到播放队列
          audioQueue.push({url, audioPlayer});
          if (!isPlaying) {
            playNextAudio();
          }
        } else if (response.error) {
          alert("错误：" + response.error);
        }
      };

      socket.onclose = () => {
        console.log("WebSocket 已关闭");
        updateStatus('未连接');
      };
    }

    function sendText() {
      const text = document.getElementById('textInput').value;
      if (socket && socket.readyState === WebSocket.OPEN) {
        socket.send(text);
      } else {
        alert("WebSocket 未连接");
      }
    }

    // Base64 to Blob
    function b64toBlob(b64Data, contentType) {
      const sliceSize = 1024;
      const byteCharacters = atob(b64Data);
      const bytesLength = byteCharacters.length;
      const slicesCount = Math.ceil(bytesLength / sliceSize);
      const byteArrays = new Array(slicesCount);

      for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
        const begin = sliceIndex * sliceSize;
        const end = Math.min(begin + sliceSize, bytesLength);
        const bytes = new Array(end - begin);
        for (let i = begin; i < end; i++) {
          bytes[i - begin] = byteCharacters.charCodeAt(i);
        }
        byteArrays[sliceIndex] = new Uint8Array(bytes);
      }
      return new Blob(byteArrays, { type: contentType });
    }

    function disconnect() {
      if (socket && socket.readyState === WebSocket.OPEN) {
        socket.close();
      }
    }
    
    // connect(); // 不再自动连接
</script>
</body>
</html>